v3.33.0+ · audyt 2026-07-18

Boss of Toys × WooCommerce

Kompleksowa dokumentacja systemu integracji WooCommerce z hurtownią BossOfToys oraz marketplace Allegro, Empik i Ceneo. Napisana na bazie bezpośredniego przeglądu kodu (core/, api/, wordpress-plugin/), a nie tylko starszych notatek — tam, gdzie kod i wcześniejsza dokumentacja się rozjeżdżały, wygrywa kod.

📅 Audyt: 2026-07-18
🔗 GitHub
🏗️ Python 3.11+ / FastAPI + WordPress (PHP)
🗄️ SQLite (WAL mode), 17 tabel
Rozdział 01

Czym jest ten system?

System Boss of Toys × WooCommerce to zautomatyzowany potok łączący hurtownię, sklep internetowy i kilka marketplace'ów w jeden spójny proces — od produktu w hurtowni, przez sklep i kanały sprzedaży, aż po dostawę do klienta i fakturę.

PlatformaRola w systemie
BossOfToys (hurtownia)Źródło produktów, stanów magazynowych i cen (XML lub REST API). Przyjmuje zamówienia dropshippingowe z etykietą PDF. Monitoring pakowania przez skrzynkę e-mail.
WooCommerce (sklep)Sklep internetowy na WordPressie (hosting OVH, domena erotivo.pl). Centralne miejsce zarządzania produktami i zamówieniami niezależnie od kanału sprzedaży.
Allegro (marketplace)Wystawianie ofert, import zamówień, fulfillment, etykiety Shipment Management, wiadomości/reklamacje, faktury, profile cenowe.
Empik (marketplace)Import zamówień przez Mirakl API — OR23 (tracking) i OR24 (potwierdzenie wysyłki).
Ceneo Kup Teraz (marketplace)Zamówienia rozpoznawane po meta _ceneo_order_guid; SetOrderShipment/SendOrder jako odpowiedniki OR23/OR24. Zintegrowane inline w module etykiet i trackingu, bez osobnego CRON-a importu.
InPost / ShipXGenerowanie etykiet (paczkomat + kurier), śledzenie paczek, Geowidget (wybór paczkomatu na checkout).
Fakturownia.plAutomatyczne wystawianie i pobieranie faktur PDF, upload do Allegro.
OpenAIGenerowanie opisów produktów — osobno dla sklepu (WooCommerce) i osobno pod ograniczenia HTML Allegro.
✅

System działa w trybie w pełni zautomatyzowanym: od pojawienia się zamówienia (sklep/Allegro/Empik/Ceneo), przez generowanie etykiety, forwarding do hurtowni, śledzenie przesyłki, aż po zamknięcie zamówienia i wystawienie faktury — bez interwencji ręcznej w normalnym przebiegu. Interwencja ręczna (przyciski w panelu WordPress) pozostaje dostępna jako fallback, gdy automat czegoś nie złapie.

⚠️

Środowisko (potwierdzone 2026-07-18): backend (VPS) działa dziś wyłącznie na Linuksie w kontenerze Docker (docker-compose.yml). Historycznie (do ~v3.32) aplikacja miała też desktopowe GUI (PyQt6) uruchamiane lokalnie na Windows — zostało całkowicie usunięte w v3.33.0. Jeśli natrafisz w starszych plikach .claude/*.md na Windows Server/PowerShell/Windows Firewall — to opis poprzedniego środowiska, zachowany jako zapis historyczny, nieaktualny dla dzisiejszej infrastruktury.

🚨

Ta dokumentacja różni się miejscami od poprzedniej wersji nie kosmetycznie, ale merytorycznie — kilka wcześniejszych ustaleń (m.in. o pluginie WordPress i module repricingu) okazało się błędnych po bezpośrednim odczycie kodu/produkcji. Tam, gdzie to istotne, rozdziały niżej wprost zaznaczają "wcześniej sądzono X, w rzeczywistości Y" — czytaj te uwagi uważnie, bo jedna z takich pomyłek doprowadziła 2026-07-18 do realnego incydentu (skasowanie zakładki Allegro na żywym sklepie, opisane w rozdziale Znane problemy i ryzyka, punkt 14).

Rozdział 02

Architektura ogólna

KLIENCI / KANAŁY SPRZEDAŻY
  │
  ├─ Sklep WooCommerce (erotivo.pl, OVH) ── klient składa zamówienie
  ├─ Allegro (marketplace) ────────────────  kupujący składa zamówienie
  ├─ Empik (marketplace, Mirakl) ──────────  kupujący składa zamówienie
  └─ Ceneo Kup Teraz (marketplace) ────────  kupujący składa zamówienie
         │  (wszystkie trafiają jako zamówienia WooCommerce, z meta
         │   rozróżniającym pochodzenie — patrz rozdział "Przepływ zamówień")
         ▼
┌──────────────────────────────────────────────────────────┐
│     WordPress (OVH) — Plugin "BeeIntegro"                │
│     (katalog: wordpress-plugin/bossoftoys-manager/)       │
│                                                            │
│  Dashboard · Harmonogram · Ustawienia                     │
│  Boss Of Toys · Allegro (pełny panel, 9+ zakładek)         │
│  Logi · Meta box etykiet · Geowidget (checkout)            │
└─────────────────┬──────────────────────────────────────────┘
                  │ HTTP (X-API-Key)  ⚠ patrz uwaga niżej — nie HTTPS
                  ▼
┌──────────────────────────────────────────────────────────┐
│     VPS — Python FastAPI (port 8000, Docker)              │
│                                                            │
│  /api/jobs/*      /api/config/*     /api/labels/*         │
│  /api/allegro/*   /api/sse/*        /api/stats/*          │
│  /api/categories/* /api/returns/*   /api/logs/*           │
│  /api/metrics      /api/status      /health                │
│                                                            │
│  SQLite: data/api_bridge.db (WAL mode, 17 tabel)           │
└─────────────────┬──────────────────────────────────────────┘
                  │
                  ▼
┌──────────────────────────────────────────────────────────┐
│     Moduły core/ (47 plików Python, od 2026-07-20)          │
│                                                            │
│  10x BossOfToys/WooCommerce   18x Allegro                  │
│  6x Etykiety/logistyka        2x Fakturownia                │
│  1x Ceneo   2x Empik   8x infrastruktura wspólna (+own_stock)│
└─────────────────┬──────────────────────────────────────────┘
                  │
     ┌────────────┼────────────┬──────────────┬─────────────┐
     ▼            ▼            ▼              ▼             ▼
BossOfToys     WC REST      Allegro        ShipX/InPost   Fakturownia /
(hurtownia)    API          OAuth 2.0      REST API       Empik / Ceneo

Komunikacja między komponentami

SkądDokądProtokół / Auth
WordPress pluginVPS FastAPIHTTP (nie HTTPS — patrz uwaga niżej) + nagłówek X-API-Key
VPSWooCommerce RESTconsumer_key + consumer_secret
VPSWordPress REST (/wp/v2)HTTPS + Application Password + Chrome User-Agent (patrz pułapka WAF niżej)
VPSBossOfToys APIemail + hasło + akronim klienta
VPSAllegro APIOAuth 2.0 — tokeny w SQLite kv_store
VPSShipX (InPost)Bearer token + organization_id
VPSFakturowniaapi_token w URL
VPSEmpik (Mirakl)API Key w nagłówku
VPSCeneo Kup TerazAPI key → Bearer token (cache TTL ok. 2h)
WordPress (zewnętrzny trigger)VPS SchedulerHTTP GET z sekretem w query string (eksport/import ofert Empik) — patrz rozdział Harmonogram CRON

Jak system rozpoznaje zamówienia z różnych kanałów

Nie ma osobnej bazy danych per kanał — wszystko jest zamówieniem WooCommerce. Kanał pochodzenia rozpoznawany jest po obecności konkretnego meta pola (szczegóły w rozdziale Przepływ zamówień i Meta WooCommerce):

Meta poleKanał
_allegro_checkout_idAllegro
_empik_order_idEmpik
_ceneo_order_guidCeneo Kup Teraz
(brak powyższych)Zamówienie sklepowe (bezpośrednio z erotivo.pl)
ℹ️

Stan pluginu WordPress — sprostowanie po incydencie z 2026-07-18: wcześniejsza wersja tej dokumentacji (i ustalenia robocze z 2026-07-17) twierdziły, że plugin WordPress jest dziś "uproszczony do command center" i że rozbudowany panel Allegro, etykiety, InPost, geowidget nie mają już odpowiednika w plikach pluginu. To było błędne — wynikało z pracy na drastycznie nieaktualnej lokalnej kopii repozytorium (`class-bot-admin.php`: 530 linii lokalnie vs 3833 na produkcji — 7-krotna różnica). Błędne ustalenie doprowadziło do nadpisania i skasowania działającej zakładki Allegro na żywym sklepie. Zweryfikowany stan faktyczny: plugin nazywa się BeeIntegro, ma pełny, rozbudowany panel Allegro (page-allegro.php, 1555 linii) i wszystkie moduły UI (etykiety, InPost, geowidget) w pełni działają. Szczegóły w rozdziale Plugin WordPress.

⚠️

OVH LiteSpeed WAF blokuje User-Agent python-requests → 403. Wszystkie requesty do /wp-json/wp/v2/* muszą używać USER_AGENT udającego przeglądarkę (Chrome string). Klucze WooCommerce (consumer_key/consumer_secret) NIE działają na WP REST API — potrzebne osobne Application Password.

🔓

WordPress → VPS to dziś zwykłe HTTP, nie HTTPS. wordpress-plugin/bossoftoys-manager/includes/class-bot-api.php (linia ok. 65) łączy się z API z jawnie ustawionym 'sslverify' => false, komentarz w kodzie wprost mówi: "Na razie wyłącz weryfikację SSL (HTTP)". Klucz X-API-Key i cała komunikacja (dane zamówień, odpowiedzi z tokenami) lecą bez szyfrowania transportu. Bezpieczeństwo opiera się wyłącznie na warstwie sieciowej. Pełna analiza ryzyka: rozdział Bezpieczeństwo.

Rozdział 03

Stos technologiczny

Backend (VPS)

KomponentTechnologiaPlik
Framework APIFastAPI ≥0.109 + uvicorn ≥0.27 (Python 3.11+)run_api.py, api/server.py
Walidacja/modelePydantic ≥2.5api/models.py
Baza danychSQLite 3 (WAL mode, foreign_keys ON)data/api_bridge.db
Repository patternWłasny, 65 metod domenowych (zliczone bezpośrednio w kodzie)api/repository.py
Migracje DBWłasny system wersjonowania (16 migracji)api/migrations.py
Adapter danychDB z fallbackiem na JSONcore/data_store.py
HarmonogramVPS Scheduler — czysty asyncio, NIE APSchedulerapi/scheduler.py
Autoryzacja APINagłówek X-API-Keyapi/auth.py
Logi real-timeServer-Sent Events (SSE)api/routes/sse.py
Telemetria HTTPMiddleware + agregacja godzinowaapi/metrics.py
WooCommerce SDKpakiet woocommerce ≥3.0core/api_clients_woo.py
Parsowanie HTML/XMLBeautifulSoup4generatory opisów
ObrazyPillow (resize/WebP)product_adder_woo.py i inne
Szyfrowanie configucryptography (Fernet)core/secure_config.py
PDFfpdf2 + fonty NotoSans (polskie znaki)core/return_pdf.py, etykiety
AI opisówOpenAI SDK ≥1.0 (opcjonalny import)description_generator_woo.py, allegro_description_generator.py
KontenerDocker (obraz bossoftoys-api:latest)docker-compose.yml
⚠️

Pełna lista zależności: requirements.txt w katalogu głównym. W repo jest też starszy, prawdopodobnie nieaktualny .claude/requirements_api.txt — jeśli oba się rozjeżdżają, ufaj requirements.txt (to ten używany realnie przez pip install -r requirements.txt wg CLAUDE.md).

Frontend (WordPress Plugin "BeeIntegro")

KomponentTechnologia
Plugin PHPWordPress 6.x + WooCommerce 8.x
JavaScriptjQuery (vanilla, bez frameworka SPA) — dashboard.js, ok. 10 400 linii
WykresyChart.js
IkonyDashicons (natywne WordPress)
Mapa InPostGeowidget InPost v5
Cache po stronie WPWordPress Transients, TTL per typ danych (class-bot-cache.php)
🔍

SSE zaimplementowane po stronie backendu i PHP, ale nieużywane w praktyce: api/routes/sse.py i class-bot-api.php mają gotowe endpointy/URL-e Server-Sent Events (w tym klucz API w query stringu URL-a, bo EventSource w przeglądarce nie pozwala na custom headers), ale zweryfikowane bezpośrednio w dashboard.js (10 414 linii) — nie ma tam aktywnego new EventSource(...). Dashboard w praktyce odpytuje przez zwykły AJAX polling (3s przy aktywnym zadaniu, 15s w spoczynku). Jeśli planujesz polegać na SSE dla nowej funkcji, zweryfikuj to jeszcze raz bezpośrednio w kodzie — może się to zmienić.

ℹ️

Backend (VPS) i plugin WordPress mają dwie niezależne numeracje wersji. Wersja aplikacji/backendu to "3.33.0+" (deklarowana w .claude/CLAUDE.md). Wersja pluginu to stała BOT_VERSION w bossoftoys-manager.php (stan 2026-07-20: 3.25.0) — służy też jako ?ver= cache-busting dla dashboard.js/admin.css. Nie próbuj ich zestawiać jako jednej, spójnej wersji systemu — to dwa oddzielne, niezsynchronizowane liczniki.

Rozdział 04

Wdrożenie i uruchomienie

Projekt działa na dwóch zupełnie oddzielnych infrastrukturach, wdrażanych i aktualizowanych niezależnie. Mylenie tych dwóch procedur jest częstym źródłem "poprawka nie działa po wdrożeniu" — patrz też rozdział Znane problemy, punkt 12.

A) VPS Linux/Docker — backend Python (`api/`, `core/`, `run_api.py`)

Użytkownik wgrywa pliki przez FileZilla/FTP na VPS, gdzie działają w kontenerze Docker.

# Uruchomienie bezpośrednio (bez kontenera, np. dev)
pip install -r requirements.txt
python run_api.py
python run_api.py --port 8080 --reload

# --- Produkcja: w Dockerze ---
docker compose up -d
docker compose logs -f
docker compose restart bossoftoys-api   # po zmianie pliku .py w api/ lub core/
🚨

Kluczowe dla zrozumienia całego procesu wdrożenia: docker-compose.yml montuje jako wolumeny ./data, ./config, ./.env oraz (od 2026-07-18) ./api:/app/api i ./core:/app/core. Wcześniej te dwa ostatnie wolumeny NIE istniały — cały kod Pythona był zaszyty na stałe w obrazie bossoftoys-api:latest, zbudowanym kiedyś, gdzieś indziej (w repo nie ma Dockerfile). Skutek: użytkownik wgrywał poprawione pliki .py przez FTP i restartował kontener, ale te pliki fizycznie nigdy nie docierały do działającego procesu — źródło całej serii pozornie niewyjaśnialnych "poprawka nie zadziałała" w historii tego projektu. Zweryfikuj, że wolumeny api/ i core/ są nadal obecne w docker-compose.yml na VPS, zanim założysz, że wgrany plik .py zacznie działać.

B) WordPress plugin (`wordpress-plugin/bossoftoys-manager/`) — hosting OVH

Zupełnie osobna infrastruktura, zwykle też FTP, ale bez Dockera i bez restartu — PHP jest interpretowane na żywo.

🚨

Zanim zrobisz nieaddytywną zmianę w wordpress-plugin/ — zweryfikuj, że lokalna kopia w repozytorium jest aktualna. Ta kopia potrafiła kiedyś być drastycznie nieaktualna (7-krotnie mniejsza niż produkcja) bez żadnego ostrzeżenia, co doprowadziło do realnego incydentu (skasowanie zakładki Allegro na żywym sklepie 2026-07-18, opis w rozdziale Znane problemy punkt 14). Szybki test: wc -l wordpress-plugin/bossoftoys-manager/includes/class-bot-admin.php — spodziewany wynik to ok. 3800 linii; jeśli wynik jest radykalnie mniejszy, kopia jest nieaktualna. Preferuj zmiany addytywne (nowa metoda/funkcja dopisana obok istniejącego kodu) nad przepisywaniem całych plików.

Minimalna konfiguracja `.env`

# WooCommerce
WOOCOMMERCE_URL=https://twojsklep.pl
WOOCOMMERCE_KEY=ck_xxxxxxxxxxxxxxxxxxxx
WOOCOMMERCE_SECRET=cs_xxxxxxxxxxxxxxxxxxxx

# WordPress REST API (media, produkty — wymaga Application Password)
WP_USERNAME=admin
WP_APP_PASSWORD=xxxx xxxx xxxx xxxx xxxx xxxx

# BossOfToys
BOSSOFTOYS_EMAIL=email@firma.pl
BOSSOFTOYS_PASSWORD=haslo
BOSSOFTOYS_ACRONYM=ESKL1_XXXX

# API security (klucz dla nagłówka X-API-Key)
API_SECRET_KEY=bardzo_dlugi_losowy_klucz_min_32_znaki

# Allegro OAuth
ALLEGRO_CLIENT_ID=twoj_client_id
ALLEGRO_CLIENT_SECRET=twoj_client_secret

# ShipX (InPost)
SHIPX_TOKEN=twoj_token_shipx
SHIPX_ORGANIZATION_ID=12345

# Fakturownia
FAKTUROWNIA_API_TOKEN=twoj_token
FAKTUROWNIA_DOMAIN=twojafirma

# Empik Marketplace
EMPIK_API_KEY=twoj_klucz_empik
EMPIK_SHOP_ID=twoj_shop_id

# Ceneo Kup Teraz
CENEO_API_KEY=twoj_klucz_ceneo

# Opcjonalne (AI, powiadomienia)
OPENAI_API_KEY=sk-xxxxxxxxxxxx
NTFY_TOPIC=twoj_temat_ntfy
SMTP_HOST=smtp.gmail.com
SMTP_USER=email@gmail.com
SMTP_PASSWORD=app_password
ALERT_EMAIL=odbiorca@gmail.com

Migracja na nowy serwer

⚠️

Pułapka przy migracji (odkryta przy przejściu Windows→Linux): config/settings.dat jest szyfrowany kluczem wyprowadzonym z adresu MAC maszyny (uuid.getnode() w core/secure_config.py). Skopiowanie tego pliku na sprzęt/kontener z innym adresem MAC powoduje cichy błąd odszyfrowania — kod loguje ostrzeżenie i traktuje config jako pusty, bez crasha. docker-compose.yml świadomie pinuje mac_address: "02:42:ac:11:00:99", żeby przynajmniej kontener był spójny sam ze sobą między restartami. Dane wrażliwe (hasła, klucze API) są bezpieczne niezależnie od tego, bo żyją w .env, nie w settings.dat (SENSITIVE_KEYS są odfiltrowywane przy zapisie) — ryzyko dotyczy tylko ustawień niewrażliwych (marże, limity, flagi modułów). Jeśli po migracji "znikają" jakieś ustawienia bez błędu w logach — to pierwsze podejrzane miejsce.

ℹ️

Pierwsze uruchomienie python run_api.py na czystym środowisku generuje i jednorazowo wypisuje w konsoli nowy API_SECRET_KEY, jeśli żaden nie jest ustawiony — trzeba go wtedy skopiować do ustawień pluginu WordPress, bo nie zostanie wyświetlony ponownie.

Rozdział 05

Konfiguracja

Priorytet ładowania (pierwszy wygrywa)

  1. Zmienne środowiskowe procesu (export WOOCOMMERCE_URL=...)
  2. Plik .env w katalogu głównym
  3. Plik config/settings.json (tryb serwerowy — obecny)
  4. Plik config/settings.dat (zaszyfrowany, relikt trybu Desktop — patrz pułapka MAC wyżej)
💾

ConfigManager (core/secure_config.py) cache'uje config w pamięci procesu. Po zapisie configu przez API wywoływana jest inwalidacja cache'a automatycznie — nie trzeba tego robić ręcznie z zewnątrz.

Sekcje konfiguracji

SekcjaZawartość
woocommerceURL, klucze API, WP credentials (Application Password)
bossoftoysDane logowania, tryb danych (api/xml), marże per kategoria
allegroOAuth (client_id/secret), min_stock, price_margin, GPSR, dostawa, pickup, kategorie
boss_apiauto_forward, dane logowania do forwardingu
shipxToken ShipX, organization_id
fakturowniaToken API, domena
empikAPI key, shop_id
ceneoAPI key (Ceneo Kup Teraz)
ntfyTopic powiadomień push (zwykłe + alerts_topic dla krytycznych)
smtpKonfiguracja e-mail dla alertów
openaiKlucz API OpenAI (opisy AI)

Harmonogram VPS — plik `config/scheduler.json`

Struktura pliku ma dwie części: jobs (moduły uruchamiane cyklicznie przez VPS Scheduler) i http_triggers (zewnętrzne wywołania HTTP GET do WordPressa, głównie dla Empika). Pełna, aktualna zawartość jobs — patrz rozdział Harmonogram CRON.

🔑

Sekcja http_triggers w config/scheduler.json zawiera żywe URL-e z sekretem uwierzytelniającym w query string (parametr secret=..., wywołania action=export_offers/import_orders/export_products na erotivo.pl dla Empika). Nie kopiuj tych URL-i do żadnej dokumentacji, logu, PR-a ani zgłoszenia — traktuj je jak hasło.

ℹ️

VPS Scheduler (api/scheduler.py, czysty asyncio, niezależny od WP-Cron i od APScheduler) zastępuje WP-Cron dla wszystkich modułów cyklicznych. WP pseudo-cron działa tylko przy odwiedzinach strony, więc nie nadaje się do niezawodnego automatyzowania — w panelu WordPress warto mieć WP-Cron wyłączony dla zadań, które przejął scheduler VPS. Zmiana w scheduler.json jest podchwytywana automatycznie, bez restartu procesu.

Rozdział 06

Baza danych SQLite

Plik: data/api_bridge.db — WAL mode + PRAGMA foreign_keys=ON. Cały trwały stan aplikacji żyje w jednym pliku.

Architektura dostępu do danych

core/*.py
   └─ from core.data_store import data_store   (import LOKALNY, wewnątrz funkcji!)
         └─ core/data_store.py (adapter)
               ├─ tryb serwerowy (VPS): api/repository.py → api/database.py → SQLite
               └─ fallback: pliki JSON (relikt trybu Desktop, dziś praktycznie nieużywany)
🚫

Zasada krytyczna, świadoma konwencja projektu — nie "napraw" jej: moduły w core/ nigdy nie importują api.repository bezpośrednio (circular import przez Pydantic). Zawsze przez core.data_store, i zawsze lokalnie, wewnątrz funkcji (from core.data_store import data_store na początku funkcji, nie na górze pliku).

17 tabel bazy danych (stan zweryfikowany bezpośrednim zapytaniem SQL do żywej data/api_bridge.db, 2026-07-18)

TabelaZawartośćRetencja
jobsHistoria uruchomień modułów (tabela bazowa, tworzona w api/database.py, nie w migracjach)7 dni
job_logsLogi z wykonań zadań (tabela bazowa)7 dni (CASCADE)
schema_migrationsWersje zastosowanych migracji DBTrwałe
kv_storeKlucz-wartość: tokeny OAuth Allegro, checkpointy, cursory eventówTrwałe dla tokenów
allegro_synced_ordersHistoria sync zamówień Allegro → WC (deduplikacja)Trwałe (nigdy nie kasowane)
forwarded_ordersZamówienia przekazane do BossOfToys (deduplikacja)Trwałe (nigdy nie kasowane)
job_resultsWyniki zadań (JSON)7 dni (CASCADE)
cache_entriesCache SKU, EAN, stany magazynowe, dopasowania katalogoweTTL per wpis
allegro_eventsZdarzenia z Allegro Events APIMax 500 wpisów
allegro_fulfillment_stateStan fulfillmentu ofert AllegroTrwałe
ghost_trackerDaty nieobecności produktów u dostawcy (Stock Sync, Product Deleter)Aktywne
run_statsStatystyki uruchomień modułówAktywne
metrics_hourlyMetryki HTTP API (agregacja godzinowa)48h
returned_shipmentsZwroty przesyłek (moduł Zwrotów, api/routes/returns.py)Trwałe
return_notesNotatki do zwrotów + meta kolumny returned_shipments (migracja 13)Trwałe
markup_profilesProfile narzutów Allegro — nazwane zestawy marż per kategoria WCTrwałe
tier_profilesProfile przedziałów cenowych Allegro — progi cena_hurtowa→narzut% per kategoria, w tym kolumna tier_tables (JSON, dodana migracją 16 — patrz uwaga niżej)Trwałe
🔍

tier_tables to KOLUMNA, nie osobna tabela — nazwa migracji #16 w rejestrze (api/migrations.py::MIGRATIONS) jest myląca i sugeruje nową tabelę, ale w rzeczywistości to ALTER TABLE tier_profiles ADD COLUMN tier_tables TEXT NOT NULL DEFAULT '[]' + backfill grupujący istniejące category_tiers o identycznej treści w nazwane, współdzielone zestawy. Potwierdzone zarówno odczytem _migration_016_tier_tables(), jak i żywym zapytaniem SELECT name FROM sqlite_master WHERE type='table' do produkcyjnej bazy — wynik to 17 tabel aplikacji (plus wewnętrzna, autogenerowana sqlite_sequence, która nie jest tabelą aplikacji).

⚠️

Liczba tabel/migracji rośnie z czasem (16 migracji na 2026-07-18, wcześniej dokumentacja podawała "13 tabel" — to był stan sprzed migracji 12-16, dodających zwroty i profile cenowe). Przed dodaniem nowej migracji zawsze sprawdź faktyczny koniec listy MIGRATIONS w api/migrations.py — plan multi-account Allegro (.claude/plan_multi_account_allegro.md) zakłada np. że wolny numer to #12, co jest już nieaktualne (#12 to od dawna returned_shipments). Użyj len(MIGRATIONS) + 1, nie numeru wpisanego w starym dokumencie.

Profile narzutów i przedziałów cenowych (nowość — `core/allegro_markup_profiles.py`)

Dwa niezależne mechanizmy cenowe, oba z dopasowaniem kategorii WooCommerce po prawdziwej hierarchii ID (rodzic/dziecko), nie po dopasowaniu tekstowym nazw:

Gdy żaden profil danego typu nie jest aktywny, zachowanie jest w 100% zgodne z poprzednim, prostszym mechanizmem marż — zero ryzyka dla instalacji, które nie korzystają z tej funkcji.

💡

Migracje uruchamiają się automatycznie przy starcie serwera (run_migrations() wołane w lifespan() serwera FastAPI) — nie wymagają ręcznej obsługi.

Rozdział 07

Moduły — BossOfToys / WooCommerce

📊
Stock Sync
stock_synchronizer_woo.py
Synchronizacja stanów magazynowych z BossOfToys do WC. Tryb różnicowy — wysyła tylko zmiany (ostatnio znane stany w kv_store). Ghost tracking — produkty nieobecne przez X dni są zerowane.
➕
Product Adder
product_adder_woo.py
Dodaje nowe produkty do sklepu. Przelicza ceny z marżą per kategoria. Tworzy kartotekę w Fakturowni. Upload zdjęć przez FTP (ftp_uploader.py). Obsługa checkpoint (resume po przerwaniu).
🗑️
Product Deleter
product_deleter_woo.py
Usuwa produkty nieobecne u dostawcy przez X dni. Sanity check: blokada przy spadku >30% katalogu jednorazowo. Domyślnie DRY-RUN!
💰
Price Updater
price_updater_woo.py
Aktualizuje ceny wg cennika BossOfToys + marże per kategoria. Próg zmiany: 0.02 PLN. Zapisuje _cost_price.
✍️
Description Generator
description_generator_woo.py
Generuje opisy sklepowe AI (OpenAI). Znacznik <!-- AI_DESC:YYYY-MM-DD -->. Backup oryginałów, resume, retry 3×. Osobny moduł od generatora pod Allegro (patrz niżej).
📤
Order Forwarder
order_forwarder_woo.py
Przekazuje zamówienia WC do BossOfToys z etykietą PDF. Nie generuje etykiet — wymaga, żeby już istniały. Deduplikacja przez tabelę forwarded_orders. Pomija zamówienia w 100% z "własnego towaru" (patrz niżej).
🏠
Own Stock nowość 2026-07-20
own_stock.py
Biblioteka pomocnicza (bez run(), nie job) — flaga _own_stock_item na produkcie. Używana przez Order Forwarder i Label Auto Generator, żeby pomijać forward zamówień ze zwrotami sprzedawanymi wyłącznie w sklepie.
🔌
Boss API Client
boss_api_client.py
Klient REST API BossOfToys do zamówień (osobny od klienta produktowego w api_clients_woo.py). Biblioteka, nie samodzielny job.
📧
Boss Packing Monitor
boss_packing_monitor.py
Loguje się przez IMAP na skrzynkę, szuka maili od system@boysoftoys.pl z numerami zamówień (wzorzec ZS-XXXXX/XX/XXXX) i oznacza odpowiednie zamówienia WC jako spakowane. Meta: _boss_packed_at.
🔔
Order Notifier
order_notifier.py
Powiadomienia NTFY o nowych zamówieniach WC, polling co N minut. Celowo zastępuje webhook WC→VPS — komentarz w kodzie wprost mówi, że webhook "nie działa przez Tailscale".

Szczegóły modułu Order Forwarder

⚠️

Order Forwarder sprawdza etykietę PDF PRZED tworzeniem zamówienia BossOfToys. Jeśli etykieta nie istnieje — zamówienie jest pomijane i moduł spróbuje ponownie w następnym cyklu CRON. Nigdy nie duplikuje zamówień dzięki tabeli forwarded_orders.

Tryb auto_forward: jeśli boss_api.auto_forward=true, forwarding odbywa się inline po wygenerowaniu etykiety w label_auto_generator.py — bez potrzeby osobnego CRON-a Order Forwarder. Produkcyjny config/scheduler.json ma mimo to Order Forwarder włączony (co 15 min) jako niezależny mechanizm nadrabiający zamówienia, które z jakiegoś powodu ominęły ścieżkę auto-forward.

Własny towar / zwroty — moduł "Own Stock" (own_stock.py, nowość 2026-07-20)

Scenariusz biznesowy: klient odsyła oryginalnie zapakowany zwrot, sklep chce go odsprzedać wyłącznie we własnym sklepie (nie na Allegro). Produkt jest duplikowany natywną funkcją WooCommerce "Duplikuj", dostaje sztuczny SKU i EAN (nigdy nieobecne u dostawcy BossOfToys), i jest wystawiany z realną ilością posiadaną fizycznie.

📋

Przy duplikacji produktu pamiętaj o polu EAN — WC "Duplikuj" nie czyści go automatycznie. Projekt ma dwa miejsca przechowywania EAN: natywne global_unique_id (pole "GTIN, UPC, EAN lub ISBN" w zakładce Zapasy) oraz legacy custom meta _gtin (czytane jako pierwsze przez allegro_scanner.py przy dopasowywaniu do katalogu Allegro). Oba trzeba wyczyścić/zmienić, inaczej duplikat może się dopasować do prawdziwej oferty Allegro po EAN mimo że nigdy nie ma tam trafić.

🗑️

Zastąpiony i usunięty mechanizm home_stock_qty: wcześniejsza, ilościowa wersja tej funkcji (pole dodające się do stanu z hurtowni) została całkowicie usunięta 2026-07-20 — nie miała UI w WordPressie, rejestr w produkcyjnej bazie był pusty (nieużywany), i miała realną lukę bezpieczeństwa (brak wykluczenia w product_deleter_woo.py). Jeśli natrafisz na wzmiankę o home_stock_qty/HOME_STOCK_META w starszych notatkach — to relikt.

🕵️

Znalezisko przy odczycie kodu: plik core/boss_auto_forwarder.py ("Automatyczne przekazywanie zamówień do BossOfToys") istnieje w core/, ale nie jest importowany z żadnego innego pliku .py w repo (ani api/, ani inny moduł core/) — sprawdzone bezpośrednim grepem. Wygląda na kod zastąpiony przez order_forwarder_woo.py + flagę auto_forward, pozostawiony w drzewie bez usunięcia. Zanim go dotkniesz lub usuniesz, potwierdź z użytkownikiem, że rzeczywiście jest martwy — grep nie wyklapie dynamicznego importu, gdyby taki gdzieś istniał.

Rozdział 08

Moduły — Allegro Marketplace

18 plików w core/allegro_*.py — największy pojedynczy obszar integracji w projekcie. Wspólny klient (allegro_client.py) obsługuje OAuth 2.0 i dziesiątki metod REST; api/routes/allegro.py wystawia ok. 106 endpointów HTTP na bazie tych modułów.

#ModułPlikOpis
1Allegro Clientallegro_client.pyKlient API Allegro z OAuth 2.0. Tokeny w SQLite kv_store. Fundament dla wszystkich pozostałych modułów Allegro.
2Allegro Scannerallegro_scanner.pySkanuje produkty WC → dopasowanie do katalogu Allegro po EAN/GTIN. Cache TTL 7 dni. Respektuje checkbox _allegro_exclude (nowość 2026-07-22) — produkty z tą flagą nigdy nie trafiają do listy dopasowanych, nawet z prawdziwym EAN.
3Allegro Listerallegro_product_lister.pyWystawia oferty. Smart zdjęcia (deduplikacja URL), HTML→sekcje Allegro, GPSR, kategoria overrides, retry parametrów po 422.
4Allegro Order Syncallegro_order_sync.pyImportuje zamówienia Allegro → WC. Ustawia attribution "Allegro" (drugi PUT po zapisie). Deduplikacja przez allegro_synced_orders.
5Allegro Offer Syncallegro_offer_sync.pySynchronizuje stany/ceny WC → oferty Allegro. Kończy oferty przy zerowym stanie, reaktywuje po powrocie. Obsługuje profile narzutów/przedziałów cenowych.
6Allegro Fulfillmentallegro_fulfillment_sync.pyStatusy WC → Allegro (completed → SENT). Wysyła numer trackingu.
7Allegro Messagingallegro_messaging_sync.pyAutoresponder wiadomości od kupujących. Uruchamiany co 5 min.
8Allegro Eventsallegro_events_poller.pyPoller zdarzeń Allegro. Max 500 zdarzeń w DB. Cursor trzymany w kv_store.
9Allegro Cost Backfillallegro_cost_backfill.pyUzupełnia _cost_price z BossOfToys — dane wejściowe do modułu rentowności.
10Allegro Category Syncallegro_category_sync.pySynchronizacja kategorii Allegro → WooCommerce (tryby preview i sync). Ostrożnie — run() (nie run_preview()) CAŁKOWICIE nadpisuje pole categories produktów wystawionych na Allegro kategorią z taksonomii Allegro, gubiąc kategorię z hurtowni. Spowodowało to realny incydent 2026-07-22 (11 475 produktów ze złą kategorią) — patrz rozdział Znane problemy.
11Allegro Params Syncallegro_params_sync.pySync parametrów ofert Allegro → atrybuty WC (tryby preview i sync).
12Allegro Label Generatorallegro_label_generator.py3-krokowy flow etykiet Shipment Management (patrz rozdział Etykiety). Wywoływany inline przez label_auto_generator.py, nie jako osobny job.
13Allegro Pickup Schedulerallegro_pickup_scheduler.pyAutomatyczne zamawianie podjazdu kuriera. Per-przewoźnik: InPost/GLS/UPS skip, DPD optional, DHL must_schedule.
14Allegro Health Monitorallegro_health_monitor.pyCRON co 60 min. Sprawdza ważność tokenu OAuth i odpowiedź API. Przy rozłączeniu wysyła krytyczne NTFY (z 2h cooldownem, żeby nie zalać powiadomieniami).
15Allegro Markup Profilesallegro_markup_profiles.pyProfile narzutów i przedziałów cenowych — patrz opis w rozdziale Baza danych.
16Allegro Description Generatorallegro_description_generator.pyGenerator opisów AI pod ograniczenia HTML Allegro (dozwolone <p> <b> <i> <u> <ul> <ol> <li> <h1-3>; zabronione m.in. <br> <strong> <em> <img> <a>). Osobny model/logika od generatora sklepowego.
17Issues (dyskusje/reklamacje)w allegro_client.pyAPI beta.v1 (GET /sale/issues) — GET /sale/disputes zostało wycofane przez Allegro 2026-01-07.
18Allegro Invoice Uploadallegro_invoice_upload.pyPrawdopodobnie martwy kod — patrz uwaga niżej.
🕵️

Dwa znaleziska "martwego kodu" przy weryfikacji tego rozdziału:

Ważne gotcha — Allegro API (raz odkryte, nie odkrywaj drugi raz)

ProblemPoprawne rozwiązanie
Pobieranie etykiety PDFDwa różne wywołania w realnym kodzie (allegro_client.py), łatwo je pomylić: POST /shipment-management/label wysyła Accept: application/octet-stream i zwykle dostaje PDF bezpośrednio w odpowiedzi (fallback: JSON z labelId, jeśli PDF nie jest gotowy od razu); dopiero gdy trzeba dociągnąć PDF osobno przez GET /shipment-management/label/{labelId}, nagłówkiem jest Accept: application/pdf (nie octet-stream). Zweryfikowane bezpośrednio w kodzie 2026-07-18 — starsze notatki projektu podawały tylko jeden z tych dwóch wariantów.
Status przy tworzeniu ofertyHTTP 202 (Accepted) to sukces — _make_request() musi akceptować [200, 201, 202, 204]
Brak dryRun przy tworzeniu ofertPOST /sale/product-offers?dryRun=true ignoruje parametr po cichu i tworzy prawdziwą ofertę. Jedyny endpoint z realnym wsparciem dryRun to PUT /sale/product-offers/{id} (edycja).
Opisy — niedozwolone tagi<br> niedozwolony, zamień na </p><p>. Dozwolone inline: <b>, <i>, <u>. Zabronione: <img>, <a>, <span>, <div>, <table>
Zdjęcia w ofercieTablica URL-i: ["https://..."], NIE obiektów [{"url": "..."}]. WooCommerce potrafi zwracać zduplikowane zdjęcia (główne + galeria) — trzeba deduplikować.
GPSR payloadZagnieżdżona struktura: producerData.tradeName, producerData.address.postalCode (nie zipCode), producerData.contact.phoneNumber (nie phone)
Parametry kategorii przy wystawianiuProdukty pod istniejącym katalogiem Allegro DZIEDZICZĄ parametry — wysłanie ich w payloadzie oferty daje 422. Wzorzec: wyślij ofertę BEZ parametrów, jeśli Allegro zwróci MissingRequiredParameters → dociągnij brakujące z katalogu i spróbuj ponownie.
Limity/messaging/threads i .../messages — max limit=20 (422 powyżej). /orders — limit do 1000.
Sprawdzanie autoryzacji AllegroSprawdzaj client_id + client_secret — NIE access_token (tokeny są w SQLite, nie w configu)
Tracking statusstatuses[-1] (OSTATNI = najnowszy), odpowiedź API jest chronologiczna
Endpoint etykiety/shipment-management/label/commands NIE ISTNIEJE (404). Używaj POST /shipment-management/label
Sandbox ≠ produkcjaBraki uprawnień/danych katalogowych na sandboxie nie muszą występować na produkcji i odwrotnie — nie diagnozuj środowiska produkcyjnego na podstawie zachowania sandboxa bez potwierdzenia.

Mapowanie statusów fulfillment

WooCommerceAllegro
processing / on-holdPROCESSING
completedSENT
cancelled / refunded / failedCANCELLED
ℹ️

Allegro nie ma statusu "DELIVERED" dla kurierów w kontekście fulfillmentu — SENT jest statusem końcowym pozytywnym. Status faktycznej dostawy śledzony jest osobno przez Shipment Management API (patrz rozdział Etykiety).

🚫

Ręczne wykluczenie produktu z Allegro (_allegro_exclude, checkbox na karcie produktu, nowość 2026-07-22): sprawdzane wyłącznie w allegro_scanner.py (zero kosztu, meta_data już pobierane per produkt) — wykluczony produkt nigdy nie trafia do listy dopasowanych. Świadomie NIE sprawdzane w allegro_product_lister.py (w przeciwieństwie do sku_blacklist, sprawdzanego tam drugi raz jako zabezpieczenie przed nieświeżym preview) — Lister nie ma dziś żadnej zależności od WooCommerceClient, działa wyłącznie na zapisanym snapshocie ze skanowania. Jeśli zaznaczysz checkbox PO skanowaniu, ale wystawisz z tego samego (już nieaktualnego) preview — produkt może się jednak wystawić. Zawsze skanuj ponownie przed wystawianiem, jeśli mogłeś zmienić ten checkbox w międzyczasie.

⚠️

Multi-konto Allegro to plan, nie rzeczywistość. .claude/plan_multi_account_allegro.md (2026-06-11) opisuje 10 błędów architektonicznych blokujących dodanie drugiego konta i proponuje naprawę fazową — status "gotowy do implementacji", ale nic z planu nie zostało wdrożone (zero odniesień do account_name w allegro_client.py). Kod dziś zakłada jedno, hardkodowane konto (erotivo_pl). Nie projektuj zmian tak, jakby wielokontowość już istniała.

Rozdział 09

Moduły — Etykiety i Wysyłka

Label Auto Generator (CRON) — centralny moduł automatyzacji wysyłki

Plik: core/label_auto_generator.py.

Zamówienie "processing" bez etykiety
  │
  ├─ _allegro_checkout_id JEST     → Allegro Shipment Management API
  └─ _allegro_checkout_id BRAK     → ShipX (InPost) API

Po wygenerowaniu etykiety:
  ├─ Zapis PDF: data/labels/label_{order_id}.pdf
  ├─ Meta WC: _*_shipment_id, _*_tracking_number, _shipping_label_source
  ├─ Ceneo: jeśli zamówienie ma _ceneo_order_guid → SetOrderShipment (tracking)
  ├─ Empik: jeśli zamówienie ma _empik_order_id → OR23 (tracking) inline
  ├─ Pickup Scheduling (Allegro, inline, non-fatal błędy)
  ├─ Auto-forward do BossOfToys (jeśli auto_forward=true)
  └─ NTFY/e-mail przy błędach

3-krokowy flow Allegro (`allegro_label_generator.py`)

Smart wymiary paczek InPost

RozmiarWymiaryMax wagaMeta produktu
A64 × 38 × 8 cm5 kg_inpost_parcel_size = a
B64 × 38 × 19 cm10 kg_inpost_parcel_size = b
C64 × 38 × 41 cm25 kg_inpost_parcel_size = c
Kurierwymusza kuriera—_inpost_parcel_size = courier

System bierze największy gabaryt ze wszystkich produktów w zamówieniu. PHP hook (class-bot-inpost-sizes.php) kopiuje meta z produktu do line item przy składaniu zamówienia.

Pickup Scheduling (`allegro_pickup_scheduler.py`)

KurierZachowaniePowód
InPostskipBossOfToys ma umowę (codzienny odbiór)
GLSskipBossOfToys ma umowę
UPSskipBossOfToys ma umowę
DPDoptionalUstna umowa, konfigurowalne
DHLmust_scheduleBrak umowy — zawsze scheduluj

Shipment Tracking (`shipment_tracking.py`)

CRON co 120 min. Trzy źródła danych równolegle:

ŹródłoDotyczyKluczowy status → akcja
ShipX APIzamówienia z _shipx_shipment_idcollected_from_sender → WC auto-complete
Allegro Tracking APIzamówienia z _allegro_shipment_idIN_TRANSIT → WC shipped, DELIVERED → WC completed → Fakturownia → upload faktury do Allegro → Fulfillment sync SENT
Ceneo (inline, ten sam moduł)zamówienia z _ceneo_order_guidprzy statusie collected_from_sender i braku _ceneo_send_order_sent → SendOrder (odpowiednik OR24)

Zwroty przesyłek — moduł "Zwroty" (`return_pdf.py`, `api/routes/returns.py`)

Osobny, mniej udokumentowany w starszych materiałach podsystem: rejestruje zwroty/nieodebrane paczki w tabelach returned_shipments i return_notes, wystawia 5 endpointów w api/routes/returns.py. core/return_pdf.py generuje zbiorczy PDF ze zwrotami (fpdf2 + fonty NotoSans dla polskich znaków) jako dowód dla hurtowni BossOfToys. Wspierające skrypty w scripts/: backfill_returns.py, import_real_return.py, seed_test_return.py.

Rozdział 10

Moduły — Integracje zewnętrzne

Fakturownia.pl

Plik: core/fakturownia_client.py, core/fakturownia_lump_sum_fix.py.

Empik Marketplace — OR23 i OR24 (Mirakl API)

Plik: core/empik_client.py, core/empik_price_sync.py.

OperacjaCo robiKiedyMeta WC
OR23Wysyła numer trackingu do EmpikaInline po wygenerowaniu etykiety_empik_carrier_tracking_number
OR24Potwierdza wysyłkę → Empik SHIPPEDCRON shipment-tracking gdy kurier odebrał_empik_or24_sent = "1"

Warunek automatycznego OR24: _empik_order_id JEST + _empik_carrier_tracking_number JEST + _empik_or24_sent BRAK + status WC = collected_from_sender LUB shipped/completed.

💡

Jeśli CRON nie wyśle OR24 automatycznie, dostępny jest ręczny przycisk "Wyślij OR24" w meta boxie etykiety na zamówieniu WooCommerce (fallback świadomie zaprojektowany na wypadek race condition — patrz rozdział Znane problemy).

Import/eksport ofert i zamówień Empik odbywa się przez http_triggers w config/scheduler.json — VPS Scheduler cyklicznie odpytuje URL-e na erotivo.pl (action=export_offers, import_orders, export_products) zabezpieczone sekretem w query string, nie przez bezpośrednie wywołanie Pythona.

Ceneo Kup Teraz — integracja bez osobnego CRON-a

Plik: core/ceneo_client.py (klasa CeneoClient, BasketService + AuthorizationService).

Metoda klientaRolaOdpowiednik
ConfirmOrderPotwierdzenie przyjęcia zamówienia—
SetOrdersPowiązanie zamówienia Ceneo z ID zamówienia WC—
SetOrderShipmentWysłanie numeru trackingu — wołane inline z label_auto_generator.pyodpowiednik Empik OR23
SendOrderPotwierdzenie wysyłki — wołane inline z shipment_tracking.pyodpowiednik Empik OR24

W przeciwieństwie do Empika i Allegro, Ceneo nie ma własnego modułu importu zamówień ani osobnego wpisu w ModuleType/MODULE_MAP — logika jest wpleciona bezpośrednio w label_auto_generator.py i shipment_tracking.py, sterowana obecnością meta _ceneo_order_guid na zamówieniu WC. Token uwierzytelniający cache'owany z TTL ok. 2h (odświeżanie z zapasem 200s przed wygaśnięciem 7200s).

OpenAI — generowanie opisów

Dwa niezależne generatory, bo mają różne ograniczenia formatu docelowego:

Rozdział 11

Plugin WordPress — "BeeIntegro"

🚨

Ten rozdział opisuje zweryfikowany stan faktyczny z 2026-07-18, po incydencie opisanym w rozdziale Znane problemy (punkt 14). Wcześniejsze wersje dokumentacji projektu twierdziły, że ten plugin jest "uproszczony do command center" bez UI Allegro/etykiet/InPost/geowidgetu — to było błędne ustalenie oparte na nieaktualnej lokalnej kopii repozytorium, nie na stanie produkcyjnym. Zawsze zweryfikuj rozmiar kluczowych plików przed edycją (patrz na końcu tego rozdziału) — lokalna kopia może się ponownie zdezaktualizować.

Plugin w interfejsie WordPress nazywa się BeeIntegro (nie "BossOfToys Manager" — to nazwa historyczna/wewnętrzna katalogu). Deployowany osobno od VPS/Dockera, zwykle FTP bezpośrednio do wp-content/plugins/bossoftoys-manager/ na hostingu OVH.

Struktura plików (stan 2026-07-20)

bossoftoys-manager/
├── bossoftoys-manager.php           # główny plik, require_once x11, stała BOT_VERSION (3.25.0)
├── readme.txt
├── includes/
│   ├── class-bot-api.php             (415 linii)  — komunikacja z VPS API (BOT_API)
│   ├── class-bot-admin.php          (3833 linie!) — menu, WSZYSTKIE 134 AJAX handlery,
│   │                                                 w tym cały backend UI Allegro
│   ├── class-bot-cron.php            (572 linie)  — WP-Cron (niezależny od VPS schedulera)
│   ├── class-bot-cache.php           (277 linii)  — cache WP Transients (BOT_Cache, TTL/typ)
│   ├── class-bot-allegro-orders.php  (385 linii)  — integracja zamówień Allegro z WC Orders
│   ├── class-bot-labels.php         (1062 linie)  — meta box etykiet na zamówieniu WC
│   ├── class-bot-geowidget.php       (366 linii)  — widget wyboru paczkomatu na checkout
│   ├── class-bot-inpost-sizes.php    (325 linii)  — gabaryty InPost per produkt
│   ├── class-bot-own-stock.php        (99 linii)  — NOWOŚĆ 2026-07-20: checkbox "własny towar"
│   │                                                 (zwroty) w zakładce Zapasy + kolumna produktów
│   ├── class-bot-order-meta.php      (222 linie)  — meta boxy (Ceneo GUID, InPost) + ostrzeżenie
│   │                                                 "wysyłasz Ty" (2026-07-20)
│   ├── class-bot-order-list.php      (248 linii)  — kolumny/filtry na liście zamówień WC + kolumna
│   │                                                 "Własny towar" (badge 🏠, 2026-07-20)
│   └── class-bot-ntfy.php            (130 linii)  — powiadomienia NTFY z poziomu WP
├── admin/
│   ├── views/
│   │   ├── dashboard.php             (603 linie)  — Dashboard ("BeeIntegro", bot-dashboard-4)
│   │   ├── page-allegro.php         (1555 linii!) — CAŁY panel Allegro (multi-tab)
│   │   ├── page-bossoftoys.php       (661 linii)  — panel hurtowni Boss Of Toys
│   │   ├── page-logs.php             (106 linii)  — przegląd logów systemowych
│   │   ├── schedule.php              (338 linii)  — harmonogram (UI WP-Cron + VPS scheduler)
│   │   └── settings.php              (709 linii)  — ustawienia (WooCommerce, BossOfToys, Allegro…)
│   ├── js/dashboard.js              (10414 linii!) — CAŁA logika JS (AJAX, wykresy, polling)
│   └── css/admin.css                 (7285 linii) — style
└── assets/
    ├── img/logo.png
    ├── css/geowidget.css
    └── js/geowidget.js

Menu w panelu WP

Top-level: BeeIntegro. Submenu (6 stron, każda osobny plik w admin/views/): Dashboard, Harmonogram, Ustawienia, Boss Of Toys, Allegro, Logi.

Wzorzec AJAX (do naśladowania przy nowych funkcjach)

Dokładnie ten wzorzec posłużył do dodania funkcji "Podsumowanie błędów" 2026-07-18 (bot_get_error_digest → ajax_get_error_digest() → BOT_API::get_error_digest() → GET /api/logs/error-digest) — dobry, świeży przykład do skopiowania przy kolejnych dodatkach.

Cache (`class-bot-cache.php` / `BOT_Cache`)

WordPress Transients z TTL per typ danych: TTL_STATS=600s, TTL_ALLEGRO_STATS=900s, TTL_CONFIG=3600s, TTL_CATEGORIES=86400s, TTL_METRICS=1800s. Wzorzec użycia: BOT_Cache::get($key, function() { ...fetch... }, $ttl). Nie każdy handler musi z tego korzystać — np. "Podsumowanie błędów" świadomie NIE cache'uje, bo świeżość ważniejsza od wydajności przy debugowaniu.

Kluczowe hooki WooCommerce

Hook WooCommerceAkcja
woocommerce_order_status_processingPlanuje pobranie faktury z Fakturowni (60s opóźnienie)
woocommerce_order_status_completedPobiera fakturę + upload do Allegro (jeśli zamówienie Allegro)
woocommerce_order_status_changed → completedWysyła fulfillment do Allegro: completed → SENT
woocommerce_new_order_itemKopiuje _inpost_parcel_size z produktu do line item

Meta box etykiety (`class-bot-labels.php`)

Wyświetlany na stronie zamówienia WC. Zawiera:

Jak sprawdzić, czy lokalna kopia jest aktualna

wc -l wordpress-plugin/bossoftoys-manager/includes/class-bot-admin.php
# Oczekiwane: ~3800 linii. Jeśli wynik jest radykalnie mniejszy (np. ~500) —
# kopia lokalna jest nieaktualna. Zatrzymaj się i poproś użytkownika o świeże pliki
# zanim cokolwiek edytujesz — patrz incydent w rozdziale "Znane problemy", punkt 14.
Rozdział 12

API REST — mapa endpointów

🔑

Wszystkie endpointy wymagają nagłówka X-API-Key: {API_SECRET_KEY}, poza dwoma wyjątkami: GET /health (bez żadnej autoryzacji) i POST /api/webhooks/wc/new-order (webhook z WooCommerce — zamiast X-API-Key opcjonalnie weryfikowany podpisem HMAC-SHA256 w nagłówku X-WC-Webhook-Signature, jeśli skonfigurowano webhooks.wc_order_secret; bez ustawionego sekretu żądanie przechodzi bez weryfikacji).

📡

Dla dokładnych ścieżek, parametrów i modeli request/response zawsze korzystaj z żywej dokumentacji uruchomionego serwera — GET /docs (Swagger UI) lub GET /redoc/GET /openapi.json. Ta tabela to mapa orientacyjna (rodzaje i skala endpointów, stan zweryfikowany 2026-07-17 bezpośrednim zliczeniem w kodzie) — .claude/API_DOCS.md opisuje tylko historyczną wersję 3.2.0 (ok. 18 endpointów Allegro) i nie nadąża za obecną skalą.

Routery i skala endpointów (`api/server.py::include_router`)

Plik routeraPrefiksLiczba endpointówFunkcja
api/routes/allegro.py/api/allegro/*~106Cała integracja Allegro: OAuth, skan/listing, oferty, zamówienia, wiadomości, finanse, wysyłka, promocje, eventy, bundling, GPSR, kategorie, parametry, profile cenowe
api/routes/config.py/api/config/*16Konfiguracja modułów/sekcji
api/routes/jobs.py/api/jobs/*9Uruchamianie/status/anulowanie/logi zadań (generyczny dispatcher dla 31 typów modułów)
api/routes/labels.py/api/labels/*12Etykiety ShipX/Allegro, Empik OR23/OR24, pickupy
api/routes/stats.py/api/stats/*9Statystyki dashboardu, status schedulera
api/routes/categories.py/api/categories/*5Kategorie WooCommerce↔Allegro
api/routes/returns.py/api/returns/*5Zwroty przesyłek
api/routes/sse.py/api/sse/*3Server-Sent Events (logi/dashboard live)
api/routes/params.py/api/params/*3Parametry ofert Allegro (preview/apply) — uwaga: prefiks to /api/params, nie /api/allegro/params (zweryfikowane bezpośrednio w APIRouter(prefix=...), starsza referencja w skillu projektu podawała to błędnie)
api/routes/logs.py/api/logs/*3Logi plikowe serwera + GET /api/logs/error-digest (podsumowanie błędów per moduł, zdeduplikowane, dla Dashboardu WP)
api/routes/webhooks.py/api/webhooks/*1POST /wc/new-order — webhook z WooCommerce (nieujęty w schemacie /docs)
ℹ️

Endpointy GET /api/metrics, GET /api/status, GET /api/modules, GET /health, GET / są zadeklarowane bezpośrednio w api/server.py, nie w api/routes/.

Przykładowe, często używane endpointy

MetodaEndpointOpis
POST/api/jobs/startUruchom moduł: {"module": "stock-sync", "params": {}}
GET/api/jobs/{job_id}Status zadania
GET/api/jobs/{job_id}/logsLogi zadania
POST/api/jobs/{job_id}/stopZatrzymaj zadanie
POST/api/labels/generate/{order_id}Generuj etykietę dla zamówienia
GET/api/labels/download/{order_id}Pobierz PDF etykiety
POST/api/labels/empik/or23/{order_id}Wyślij OR23 do Empika (tracking)
POST/api/labels/empik/confirm-ship/{order_id}Wyślij OR24 do Empika (SHIPPED)
GET/api/allegro/auth-urlURL do autoryzacji OAuth
GET/api/allegro/statusStatus połączenia
GET/api/allegro/offersLista ofert (paginacja, filtry)
PATCH/api/allegro/offers/{id}/priceZmień cenę oferty
POST/api/allegro/offers/bulk-price-updateZbiorcza zmiana cen (%)
GET/api/allegro/ordersLista zamówień
POST/api/allegro/orders/{id}/fulfillmentWyślij fulfillment
POST/api/allegro/orders/{id}/invoicesUpload faktury PDF do Allegro (realna ścieżka — nie moduł allegro_invoice_upload.py, patrz rozdział Allegro)
GET/api/allegro/messages/threadsWątki wiadomości
POST/api/allegro/messages/threads/{id}/replyOdpowiedz w wątku
GET/api/allegro/issuesDyskusje i reklamacje (beta.v1)
GET/api/allegro/billingRozliczenia
GET/api/allegro/profitabilityRentowność ofert
GET/api/allegro/delivery-servicesUsługi dostawy (diagnostyka)
POST/api/allegro/shipping/pickupsZamów odbiór paczek
POST/api/allegro/shipping/shipments/cancelAnuluj przesyłki
POST/api/allegro/shipping/protocolProtokół nadania PDF
GET/api/allegro/categories-treeDrzewo kategorii WC (dla profili cenowych) — patrz rozdział Znane problemy, punkt 4
POST/api/allegro/tier-profiles/import-legacyImport istniejących przedziałów jako nowy profil
GET/api/stats/schedulerStatus VPS Schedulera
GET/api/config/wp/testDiagnostyka połączenia z WordPress REST API
GET/api/logs/error-digestPodsumowanie błędów per moduł (nowość 2026-07-18)

Uruchomienie i pierwsze kroki

Rozdział 13

Przepływ zamówień

Jak system rozpoznaje typ zamówienia?

Meta zamówienia WC (sprawdzane w tej kolejności):
  ├─ _allegro_checkout_id JEST    → Zamówienie ALLEGRO
  │            Etykieta: Allegro Shipment Management
  │            Tracking: Allegro Tracking API
  │            Faktura: upload do Allegro
  │            Status: sync → Allegro SENT
  │
  ├─ _empik_order_id JEST         → Zamówienie EMPIK
  │            Etykieta: ShipX (InPost)
  │            OR23: numer trackingu do Empika (inline po etykiecie)
  │            OR24: potwierdzenie wysyłki (CRON shipment-tracking)
  │
  ├─ _ceneo_order_guid JEST       → Zamówienie CENEO KUP TERAZ
  │            Etykieta: ShipX (InPost)
  │            SetOrderShipment: numer trackingu (inline po etykiecie)
  │            SendOrder: potwierdzenie wysyłki (CRON shipment-tracking)
  │
  └─ Brak powyższych              → Zamówienie SKLEPOWE
               Etykieta: ShipX (InPost)
               Tracking: ShipX API
               Faktura: tylko lokalna (Fakturownia, bez uploadu do marketplace)

Zamówienie sklepowe — pełny flow

KROK 1 — ZŁOŻENIE
  Klient → WooCommerce → status: processing (po płatności)
  PHP hook → planuje pobranie faktury (60s)
  Geowidget → _inpost_point_id
  PHP hook → _inpost_parcel_size z produktów do line items

KROK 2 — ETYKIETA (CRON: label-generator, co 10 min)
  Brak _allegro_checkout_id → ShipX API
  Odczytuje _inpost_parcel_size → największy gabaryt
  Tworzy przesyłkę ShipX → PDF → data/labels/label_{id}.pdf
  Meta: _shipx_shipment_id, _shipx_tracking_number

  [auto_forward=true] → BossOfToys + status completed

KROK 3 — ŚLEDZENIE (CRON: shipment-tracking, co 120 min)
  ShipX API → status paczki
  "collected_from_sender" → AUTO-COMPLETE WC
  PHP hook (completed) → Fakturownia PDF

GOTOWE ✅

Zamówienie Allegro — pełny flow

KROK 1 — IMPORT (CRON: allegro-order-sync, co 10 min, hours_back=24)
  Allegro API → POST /wc/v3/orders
  Drugi PUT: _wc_order_attribution_utm_source="Allegro"
  Meta: _allegro_checkout_id, _allegro_buyer_*, _allegro_delivery_*
  PHP fix: zeruje VAT "zw" na wysyłce

KROK 2 — ETYKIETA (CRON: label-generator, co 10 min)
  Jest _allegro_checkout_id → Allegro Shipment Management
  3-krokowy flow: create → poll → label PDF
  Smart wymiary z _inpost_parcel_size
  Meta: _allegro_shipment_id, _allegro_tracking_number, _allegro_carrier
  Pickup scheduling: DHL → zamów, InPost/GLS/UPS → skip
  [auto_forward=true] → BossOfToys

KROK 3 — ŚLEDZENIE (CRON: shipment-tracking, co 120 min)
  Allegro Tracking API (/shipment-management/shipments/{id})
  statuses[-1] = najnowszy status
  IN_TRANSIT  → WC: "shipped"
  DELIVERED   → WC: "completed" → Fakturownia → upload faktury
              → Fulfillment sync: Allegro SENT

GOTOWE ✅

Zamówienie Empik

KROK 1 — IMPORT
  Empik (Mirakl) → WooCommerce przez http_trigger import_orders (meta _empik_order_id)

KROK 2 — ETYKIETA + OR23 (label-generator)
  ShipX etykieta → _shipx_shipment_id, _shipx_tracking_number
  OR23 inline: empik_client.send_tracking() → _empik_carrier_tracking_number

KROK 3 — OR24 (shipment-tracking, co 120 min)
  "collected_from_sender" + _empik_order_id + tracking + brak or24_sent
  → OR24: empik_client.confirm_ship() → Empik: SHIPPED
  → _empik_or24_sent = "1"
  (ręczny fallback: przycisk "Wyślij OR24")

GOTOWE ✅

Zamówienie Ceneo Kup Teraz

KROK 1 — IMPORT
  Zamówienie trafia do WC z meta _ceneo_order_guid (mechanizm importu
  poza core/ — sprawdź WP plugin/zewnętrzną integrację, jeśli to zadanie dotyczy)

KROK 2 — ETYKIETA + SetOrderShipment (label-generator, inline)
  ShipX etykieta → _shipx_shipment_id, _shipx_tracking_number
  SetOrderShipment inline: ceneo_client.CeneoClient(...).set_order_shipment()
  → _ceneo_tracking_sent

KROK 3 — SendOrder (shipment-tracking, co 120 min, inline)
  "collected_from_sender" + _ceneo_order_guid + brak _ceneo_send_order_sent
  → SendOrder → _ceneo_send_order_sent

GOTOWE ✅
Rozdział 14

Harmonogram CRON

Zawartość zweryfikowana bezpośrednio w config/scheduler.json produkcyjnym (2026-07-18). Wszystkie zadania jobs są dziś enabled: true.

ModułInterwałParametryPriorytet
Label Generator10 minlimit=20⭐⭐⭐ Krytyczny
Allegro Order Sync10 minhours_back=24⭐⭐⭐ Krytyczny
Allegro Fulfillment Sync10 min—⭐⭐⭐ Krytyczny
Order Forwarder15 mindry_run=false — realnie wysyła zamówienia!⭐⭐⭐ Krytyczny
Order Notifier5 min—⭐⭐ Ważny
Allegro Messaging Sync5 min—⭐⭐ Ważny
Stock Sync30 min—⭐⭐ Ważny
Allegro Offer Sync30 min—⭐⭐ Ważny
Boss Packing Monitor30 min—⭐⭐ Ważny
Allegro Health Monitor60 min—⭐ Normalny
Shipment Tracking120 minstatus=processing,shipped⭐ Normalny
Price Updater24h—⭐ Normalny
Empik Price Sync24h—⭐ Normalny
Backup24h—⭐ Normalny
Fakturownia Lump Sum Fix24hdays_back=7⭐ Normalny
ℹ️

Product Deleter nie ma dziś wpisu w config/scheduler.json (poprzednia wersja tej dokumentacji podawała go jako job dzienny z dry_run=true — nie potwierdzone w aktualnym pliku produkcyjnym). Uruchamiaj go ręcznie z panelu WordPress lub przez POST /api/jobs/start, zawsze najpierw z dry_run=true przez kilka dni, zanim przełączysz na realne usuwanie.

Zewnętrzne wyzwalacze HTTP (`http_triggers`)

Osobna sekcja w config/scheduler.json — VPS Scheduler cyklicznie wywołuje GET-y do WordPressa (nie do własnego API), głównie dla integracji Empik przez wtyczkę empik-for-woocommerce: eksport ofert (co 30 min), import zamówień (co 10 min), eksport produktów (co 24h). URL-e zawierają sekret w query string — patrz ostrzeżenie w rozdziale Konfiguracja.

Kolejność włączania (nowe wdrożenie)

Rozdział 15

Meta dane na zamówieniach WooCommerce

Kluczowe meta (routing systemu)

Klucz metaWartośćZnaczenie
_allegro_checkout_idUUIDZamówienie pochodzi z Allegro → Allegro flow
_empik_order_idstringZamówienie pochodzi z Empika → Empik flow
_ceneo_order_guidstringZamówienie pochodzi z Ceneo Kup Teraz → Ceneo flow
_shipping_label_source"allegro" / "shipx"Skąd pochodzi etykieta
_inpost_point_idstringID paczkomatu docelowego (z Geowidgetu)
_inpost_parcel_sizea/b/c/courierGabaryt paczki (na produkcie i skopiowany na line item)
_boss_packed_atISO 8601 lub pustyZamówienie potwierdzone jako spakowane przez BossOfToys (Boss Packing Monitor, IMAP)
_own_stock_handled"1"Zamówienie w 100% z własnego towaru (zwrotu) — NIE przekazane do BossOfToys. Ustawiane przez own_stock.py (nowość 2026-07-20)

Meta produktu (nie zamówienia) sterujące tym mechanizmem: _own_stock_item = yes/no, checkbox w zakładce Zapasy karty produktu. Szczegóły: rozdział Moduły — BossOfToys / WooCommerce, sekcja "Własny towar / zwroty".

Meta etykiet Allegro

KluczOpis
_allegro_shipment_idID przesyłki Allegro Shipment Management
_allegro_tracking_numberNumer śledzenia przesyłki
_allegro_carrierNazwa przewoźnika (DHL, InPost, DPD…)
_allegro_label_idID etykiety Allegro
_allegro_label_createdTimestamp wygenerowania
_allegro_pickup_scheduled / _allegro_pickup_command_idCzy i jakim poleceniem zamówiono podjazd kuriera
_allegro_shipment_status / _allegro_shipment_status_labelAktualny status (IN_TRANSIT, DELIVERED…) i jego czytelna etykieta PL
_allegro_invoice_uploadedCzy faktura została wysłana do Allegro

Meta etykiet ShipX

KluczOpis
_shipx_shipment_idID przesyłki ShipX
_shipx_tracking_numberNumer śledzenia
_shipx_statusAktualny status ShipX
_shipx_status_labelCzytelna etykieta PL
_shipx_status_updatedTimestamp ostatniej aktualizacji

Meta Empik

KluczOpis
_empik_order_idID zamówienia Empik Mirakl
_empik_carrier_tracking_numberNumer trackingu (po OR23)
_empik_or24_sent"1" po potwierdzeniu wysyłki (OR24)

Meta Ceneo

KluczOpis
_ceneo_order_guidGUID zamówienia Ceneo Kup Teraz
_ceneo_tracking_sentCzy SetOrderShipment (odpowiednik OR23) został wysłany
_ceneo_send_order_sentCzy SendOrder (odpowiednik OR24) został wysłany

Meta Attribution (Pochodzenie w WC)

KluczWartośćEfekt
_wc_order_attribution_utm_source"Allegro" / "Import z Empik"Wartość w kolumnie "Pochodzenie"
_wc_order_attribution_source_type"utm"Wymagane — bez tego WC nie wyświetla źródła
Rozdział 16

Zależności między modułami

BossOfToys API / XML
        │
        ├──────────────────────────────────┐
        ▼                                 ▼
  Stock Sync ──────────► WooCommerce    Product Adder
  Price Updater ─────────► (REST API)   Product Deleter
  Cost Backfill                │
                               │
        ┌──────────────────────┤
        │                      │
        ▼                      ▼
  Allegro Scanner ──► WooCommerce produkty (EAN)
        │
        ▼
  Allegro Lister ──────────► Allegro API (OAuth 2.0)
                                     │
        ┌────────────────────────────┤
        │                            │
        ▼                            ▼
  Allegro Order Sync          Allegro Offer Sync
        │                       (+ Markup/Tier Profiles)
        ▼                            │
  WooCommerce                        ▼
  (zamówienia,               Allegro oferty
   + Empik/Ceneo             (stany/ceny)
   przez własne wejścia)
        │
        ├──────────────────────────────────────┐
        │                                      │
        ▼                                      ▼
  Label Auto Generator                   Order Forwarder
    │      │      │                            │
    │      │      │                            ▼
    ▼      ▼      ▼                     BossOfToys API
  ShipX  Allegro  inline OR23/          (zamówienie + PDF)
  Label  Label    SetOrderShipment
    │      │      (Empik / Ceneo)
    └──┬───┘
       │
       ▼
  Shipment Tracking ──► ShipX API / Allegro Tracking API
       │
       ├──────────────► AUTO-COMPLETE WC
       ├──────────────► OR24 Empik / SendOrder Ceneo (inline, jeśli meta obecne)
       └──────────────► Fakturownia → upload faktury → Allegro SENT

Kolejność uruchamiania modułów

  1. Label Generator — etykiety muszą być pierwsze (dla wszystkich kanałów)
  2. Shipment Tracking — śledzi i auto-complete/OR24/SendOrder
  3. Order Forwarder — wymaga istniejącej etykiety
  4. Allegro Order Sync — import nowych zamówień
  5. Stock Sync — stany magazynowe
  6. Allegro Offer Sync — po sync stanów
  7. Price Updater — ceny
  8. Allegro Fulfillment Sync — na końcu (zależy od etykiet i statusów)
Rozdział 17

Bezpieczeństwo

Ten rozdział konsoliduje ustalenia bezpieczeństwa z .claude/SECURITY_SETUP.md (historyczny opis Windows Server) i audytu kodu z 2026-07-17/18. Koncepcja "dwuwarstwowego zabezpieczenia" (VPN mesh + whitelist IP) jest nadal dobrą praktyką, ale jej konkretna implementacja opisana w starym dokumencie dotyczy poprzedniego serwera Windows i wymaga potwierdzenia na obecnym VPS Linux.

Model sieciowy — do zweryfikowania na obecnym VPS

Znane, potwierdzone ryzyka

RyzykoSzczegółyStatus
Transport WordPress → VPS bez TLSclass-bot-api.php ma jawnie 'sslverify' => false — cała komunikacja (w tym X-API-Key) leci zwykłym HTTP. Bezpieczeństwo opiera się wyłącznie na warstwie sieciowej.Do potwierdzenia z użytkownikiem, czy świadome
config/settings.json.template zawiera realne sekretyMimo nazwy "template", plik zawiera klucz/secret WooCommerce i hasło do API BossOfToys wyglądające jak prawdziwe dane produkcyjne, nie placeholdery. Jeśli plik trafił kiedyś do repozytorium git, sekrety mogły wyciec do historii commitów.Do rotacji/weryfikacji
Szyfrowanie settings.dat kluczem z adresu MACuuid.getnode() w secure_config.py. Błąd deszyfrowania jest cichy — config staje się pusty bez crasha. Dane wrażliwe są bezpieczne (żyją w .env), ryzyko dotyczy tylko ustawień niewrażliwych.Wiedza operacyjna — czujność przy migracjach
Ten katalog roboczy nie jest repozytorium gitMimo że dokumentacja projektu odwołuje się do github.com/RadoslawSwider/RSJB-Bossoftoys, lokalny katalog nie ma zainicjalizowanego .git. Zmiany w plikach nie trafiają automatycznie do faktycznego repozytorium/serwera — wymaga ręcznej synchronizacji.Do ustalenia z użytkownikiem

Autoryzacja API

⚠️

Dodatkowe zabezpieczenia wskazane w starym dokumencie jako "do rozważenia w przyszłości" (i wciąż aktualne): certyfikat TLS między WordPress a VPS, rate limiting, mechanizm typu fail2ban dla portu API.

Rozdział 18

Znane problemy i ryzyka

Skonsolidowana lista z .claude/KNOWN_ISSUES.md (stan 2026-07-18) — nie jest to lista potwierdzonych, aktualnie trwających awarii, tylko udokumentowanych ryzyk i incydentów z pełną historią diagnozy. Pełne szczegóły techniczne (dowody, dokładne linie kodu) w źródłowym pliku.

#ProblemStatus
1Logi (data/logs/) nigdy się nie czyściły — zły wzorzec glob w cleanup_old_log_files() (kropki zamiast myślników w nazwie pliku)Naprawione i wdrożone 2026-07-18, niepotwierdzone wprost przez użytkownika że retencja realnie czyści; istniejący narosły balast (1.4 GB w kopii audytowej) wymaga jednorazowego ręcznego czyszczenia
2allegro-messaging-sync/allegro-events-poll — błąd sygnatury on_finish_callback() got an unexpected keyword argument 'job_id'Naprawione w punkcie kontraktu (api/worker.py przyjmuje teraz *args, **kwargs), wdrożone 2026-07-18, niepotwierdzone wprost przez użytkownika po realnym wdrożeniu
3Order Forwarder nie widział świeżo wygenerowanej etykiety (auto-forward) — klasyczny problem "write-then-read" po stronie WooCommerce REST API (prawdopodobnie cache hostingu)Naprawione (etykieta uzupełniana lokalnie ze znanych danych, nie tylko ze świeżego GET), wdrożone 2026-07-18, niepotwierdzone wprost przez użytkownika
4Profile przedziałów cenowych Allegro — "Błąd: not found" / "Błąd pobierania kategorii WooCommerce". Przy okazji znaleziono poważniejszy problem: błędy pobierania kategorii WC były całkowicie wyciszane (_silent_logger), więc niediagnozowalne z logów serwera z zasadyNaprawione i POTWIERDZONE przez użytkownika 2026-07-18 — przyczyną był najpewniej nieodświeżony obraz Dockera (patrz punkt 12), nie kod aplikacji
5storage/temp/*.xml (cache XML z BossOfToys, ~48 MB/plik) — brak widocznej logiki czyszczeniaDo obserwacji — niższe ryzyko niż logi, ale kolejny potencjalny wektor zapełnienia dysku
6WordPress → VPS to zwykłe HTTP, nie HTTPS (sslverify => false)Ryzyko bezpieczeństwa — patrz rozdział Bezpieczeństwo
7config/settings.json.template zawiera dane wyglądające jak realne sekrety zamiast placeholderówRyzyko bezpieczeństwa — do rotacji/weryfikacji
8settings.dat szyfrowany kluczem z adresu MAC — cicha utrata ustawień niewrażliwych przy migracji sprzętu/kontenera bez pinowanego mac_addressWiedza operacyjna — nic do zrobienia teraz, czujność na przyszłość
9Plan multi-account Allegro (10 znanych błędów architektonicznych, B1-B10) — w pełni opisany, nic nie wdrożonePraca do zaplanowania osobno, gdy będzie na czasie
10Duże historyczne rozjazdy dokumentacja ↔ kod (częściowo naprawione audytem 2026-07-17/18, w tym ta dokumentacja)W toku — dokumentacja bywa w tyle za kodem; traktuj ją jako punkt startowy, nie ostateczne źródło prawdy
11Numeracja migracji DB w planach (np. planie multi-account) jest nieaktualna względem faktycznego api/migrations.pyDo pamiętania — zawsze używaj len(MIGRATIONS) + 1, nie numeru z dokumentu
12Brak Dockerfile w repo — wolumeny docker-compose.yml nie obejmowały api//core/, więc wgrywany kod nigdy nie docierał do działającego kontenera. Wyjaśnia całą serię "poprawka nie działa po redeployu" (punkty 1-4)ROOT CAUSE naprawiony 2026-07-18 (dodano wolumeny ./api:/app/api, ./core:/app/core) — nadal otwarte: gdzie/jak buduje się obraz bossoftoys-api:latest
13Ten katalog roboczy nie jest zainicjalizowanym repozytorium gitDo ustalenia z użytkownikiem — nie wynika stąd bug, ale zmiany wymagają ręcznej synchronizacji z faktycznym repo/serwerem
14Incydent (rozwiązany): skasowana zakładka Allegro w WordPress 2026-07-18 — edycja pluginu na bazie drastycznie nieaktualnej lokalnej kopii repo nadpisała pełne, żywe pliki produkcyjneROZWIĄZANE — użytkownik dostarczył świeży backup, stan odtworzono, dodano trwałe zabezpieczenie proceduralne (references/wordpress-plugin.md + zasada weryfikacji rozmiaru plików przed edycją)
15Incydent (rozwiązany): allegro_category_sync.py::run() uruchomiony kiedyś na żywo nadpisał pole categories produktów wystawionych na Allegro kategorią z taksonomii Allegro zamiast hurtowni — 11 475/19 639 produktów (58%) miało złą kategorię, a drzewo kategorii miało 139 osieroconych, całkowicie martwych kategorii (0 produktów na każdym poziomie poddrzewa) z ogólnej taksonomii Allegro (np. "Części motocyklowe", "Wędkarstwo")ROZWIĄZANE 2026-07-22 — scripts/rebuild_categories_from_boss.py skorygował wszystkie 11 475 produktów (0 błędów, zero strat SEO), a 139 martwych kategorii skasowano po potwierdzeniu użytkownika. Patrz rozdział Moduły Allegro
⚠️

Wciąż niepotwierdzone wprost przez użytkownika (stan 2026-07-18): czy błędy #1 (rotacja logów), #2 (on_finish_callback/job_id) i #3 (order-forwarder bez etykiety) faktycznie przestały się powtarzać na produkcji po realnym wdrożeniu. Najszybszy sposób sprawdzenia: sekcja "Podsumowanie błędów" w Dashboardzie WordPress (GET /api/logs/error-digest, dodana 2026-07-18).

Rozdział 19

Historia wersji

⚠️

.claude/CHANGELOG.md urywa się merytorycznie na wpisach do 3.30.0/3.33.0 plus jeden wpis audytowy z 2026-07-17 — nie odnotowuje wprost dodania Ceneo, modułu zwrotów, profili narzutów/przedziałów cenowych ani usunięcia modułu repricingu. Tabela niżej łączy potwierdzone daty z changeloga z ustaleniami z bezpośredniego audytu kodu (2026-07-17/18); tam gdzie dokładna data wprowadzenia nie jest znana, jest to zaznaczone wprost zamiast zgadywane.

Wersja / dataKluczowe zmiany
2026-07-22Naprawiony incydent: allegro_category_sync.py nadpisywał kategorie WC produktów wystawionych na Allegro. Skorygowano 11 475 produktów jednorazowym skryptem scripts/rebuild_categories_from_boss.py (zero strat SEO). Dodano checkbox "Nie wystawiaj na Allegro" (_allegro_exclude, sprawdzany w allegro_scanner.py). Współdzielona logika kategorii wydzielona do core/category_utils.py. BOT_VERSION → 3.26.0.
2026-07-21Dropdown filtra "Tylko własny towar" nad listą produktów WP (class-bot-own-stock.php).
2026-07-20Nowy mechanizm "Własny towar" (own_stock.py) — odsprzedaż zwrotów wyłącznie w sklepie, bez przekazywania zamówienia do BossOfToys. Checkbox na karcie produktu, ochrona w product_deleter_woo.py, widoczność (NTFY + badge na liście zamówień + ostrzeżenie w meta boxie). Usunięty stary, nieużywany mechanizm home_stock_qty. BOT_VERSION → 3.25.0.
2026-07-18ROOT CAUSE naprawiony: wolumeny Dockera dla api//core/. Naprawy: rotacja logów, sygnatura on_finish_callback, widoczność etykiety dla order-forwarder. Nowa funkcja "Podsumowanie błędów" w Dashboardzie (/api/logs/error-digest). Incydent i odzyskanie pluginu WordPress (zakładka Allegro). Ta dokumentacja przepisana na bazie pełnego audytu.
2026-07-17Audyt architektury + nowy skill programisty erotivo-dev + aktualizacja dokumentacji pod Linux (bez zmian w kodzie produkcyjnym poza wstępnymi poprawkami wymienionymi wyżej)
nieznana data, przed 2026-07-11Profile narzutów i przedziałów cenowych Allegro (markup_profiles, tier_profiles, tier_tables — migracje 14-16); moduł zwrotów przesyłek (returned_shipments, return_notes — migracje 12-13); integracja Ceneo Kup Teraz; usunięcie modułu allegro_repricing.py (Allegro zablokowało dostęp do API cen konkurencji). Żadna z tych zmian nie ma wpisu w CHANGELOG.md — daty ustalone pośrednio (rekordy w bazie z 2026-07-11).
3.33.0 · 2026-05-21Usunięcie GUI Desktop (PyQt6), moduł etykiet API-only, allegro_category_sync + allegro_params_sync, boss_api_client, fakturownia_lump_sum_fix
3.32.0 · 2026-04-22Empik Marketplace (OR23/OR24), Allegro order attribution fix, strona logów
3.31.0 · 2026-03Webhook Circuit Breaker, Allegro Offer Sync rozszerzony, stabilność VPS Schedulera
3.30.0 · 2026-03-07Allegro Delivery (Shipment Management API), Dual Shipment Tracking, Smart wymiary InPost, Allegro Pickup Scheduler
3.29.0 · 2026-02-11Shipment Tracking (ShipX), Auto-Forward do BossOfToys, NTFY powiadomienia o błędach etykiet
3.27.0 · 2026-02-13Migracja JSON → SQLite (11 tabel na starcie, Repository pattern, adapter data_store)
3.26.0 · 2026-02-12Labels v2 (PDF na dysku VPS), deduplikacja przesyłek, wykrywanie przewoźnika
3.20.0 · 2026-02VPS Scheduler (zastępuje WP-Cron)
3.8.1 · 2026-02Fakturownia.pl (faktury + produkty), upload faktur do Allegro
3.7.0 · 2026-02-04Issues API beta.v1, UI/UX refresh panelu Allegro, finanse
3.2.0 · 2026-01-31Allegro Integration v2.0 (GPSR, dryRun, obrazy, opisy, sync, fulfillment)
3.1.0 · 2026-01BossOfToys REST API (ceny z rabatami)
3.0.0 · 2026-01WordPress Bridge, Dashboard, telemetria, Chart.js — początek architektury API+plugin (wcześniej: aplikacja desktopowa PyQt6)
Rozdział 20

Rozwiązywanie problemów

Diagnoza ogólna — pierwsze kroki

  1. Sprawdź logi VPS: WordPress → BeeIntegro → Logi, albo sekcję "Podsumowanie błędów" na Dashboardzie
  2. Status API Allegro: GET /api/allegro/status
  3. Diagnostyka WP REST API: GET /api/config/wp/test
  4. Status Schedulera: GET /api/stats/scheduler
  5. Zweryfikuj, że kontener faktycznie widzi aktualny kod: docker compose exec bossoftoys-api grep -n "fragment zmiany" /app/api/plik.py
  6. Weryfikacja składni: python -m py_compile core/nazwa_modulu.py

Allegro

Brak tokenu / "Nie połączono z Allegro"

Sprawdź czy ALLEGRO_CLIENT_ID i ALLEGRO_CLIENT_SECRET są w .env. Tokeny OAuth są w SQLite (kv_store), nie w configu — autoryzuj przez WordPress → Ustawienia → Allegro.

Zamówienia Allegro — "Pochodzenie: Nieznane"

Wymaga obu meta: _wc_order_attribution_utm_source="Allegro" ORAZ _wc_order_attribution_source_type="utm". WooCommerce może nadpisać attribution w swoim hooku — allegro_order_sync.py wykonuje drugi PUT po zapisie zamówienia właśnie z tego powodu.

Moduł Repricing zwraca błąd/wyjątek

To oczekiwane — core/allegro_repricing.py jest dziś funkcjonalnie usunięty (rzuca RuntimeError) po tym jak Allegro zablokowało dostęp do API cen konkurencji na kontach produkcyjnych. To nie jest bug do naprawienia.

Błąd 406 przy pobieraniu etykiety

Header Accept: application/octet-stream jest wymagany (NIE application/pdf!).

Endpoint etykiety 404

/shipment-management/label/commands NIE ISTNIEJE. Używaj POST /shipment-management/label.

ObjawRozwiązanie
Duplikaty przesyłek AllegroModuł sprawdza _allegro_shipment_id w meta. Duplikaty → anuluj przez panel WP → Allegro → Wysyłka → Anulowanie.
Pickup DHL się nie dziejeSprawdź allegro.pickup.carrier_overrides.DHL.auto_schedule=true. Błędy pickup schedulera są non-fatal — sprawdź logi, nie blokują reszty flow.
Oferta odrzucona — opisUsuń tagi <br>. Dozwolone: <b> <i> <u>.
Profile przedziałów cenowych: "Błąd pobierania kategorii WooCommerce"Sprawdź logi docker compose logs pod loggerem allegro_profiles (naprawiono wyciszanie błędów 2026-07-18). Najczęstsza przyczyna historyczna: nieodświeżony obraz Dockera bez najnowszych endpointów.

WooCommerce / WordPress

ObjawRozwiązanie
403 przy requestach WP REST APIOVH LiteSpeed WAF blokuje python-requests. Wszystkie requesty do /wp-json/wp/v2/* muszą używać Chrome User-Agent.
Klucze WC nie działają na /wp/v2/Normalne — WP REST API wymaga Application Password (WordPress → Użytkownicy → profil), nie kluczy WooCommerce.
Błąd generator has no len()get_orders_by_status() zwraca generator. Owijaj w list(): orders = list(woo_client.get_orders_by_status(...))
Gabaryt InPost zawsze ASprawdź _inpost_parcel_size na produktach i czy PHP hook kopiuje meta do line items przy składaniu zamówienia.
Zmiana w dashboard.js/admin.css "nie działa" mimo wgraniaCache przeglądarki po ?ver={BOT_VERSION} — zbumpuj BOT_VERSION w bossoftoys-manager.php i/lub zrób twardy refresh (Ctrl+Shift+R).
Panel Allegro/etykiety "zniknęły" po edycji pluginuPrawdopodobnie edycja na bazie nieaktualnej lokalnej kopii nadpisała pełne pliki produkcyjne. Przywróć z backupu, zweryfikuj rozmiar class-bot-admin.php (~3800 linii) przed kolejną edycją.

Empik / Ceneo

ObjawRozwiązanie
OR24 nie poszło automatycznieSprawdź czy OR23 poszedł (_empik_carrier_tracking_number w meta). CRON retryuje co 120 min. Użyj ręcznego przycisku "Wyślij OR24" jako fallback.
Ceneo SendOrder nie idzieSprawdź _ceneo_order_guid i CENEO_API_KEY w .env. Logika jest inline w shipment_tracking.py — sprawdź logi pod kątem wyjątku Ceneo SendOrder wyjątek.

Baza danych

ObjawRozwiązanie
Circular import w core/Nigdy nie importuj api.repository w core/. Używaj from core.data_store import data_store — i tylko wewnątrz funkcji.
Stary schemat DB po aktualizacjiMigracje odpalają się automatycznie przy starcie serwera. Sprawdź logi startowe pod kątem [Migration NNN].
Dane znikają po restarcieSQLite jest trwałe. Sprawdź czy data/api_bridge.db jest poprawnie zamontowane jako wolumen i nie jest nadpisywane przy deployu.
"database is locked" po migracji na inny hostingSprawdź, czym faktycznie jest zamontowane ./data na hoście — sieciowe systemy plików (NFS itp.) potrafią psuć blokady SQLite WAL.

Komendy diagnostyczne

# Weryfikacja składni Pythona
python -m py_compile core/allegro_order_sync.py

# Test połączenia Allegro
curl -H "X-API-Key: TWOJ_KLUCZ" http://vps:8000/api/allegro/status

# Test połączenia WordPress
curl -H "X-API-Key: TWOJ_KLUCZ" http://vps:8000/api/config/wp/test

# Status Schedulera VPS
curl -H "X-API-Key: TWOJ_KLUCZ" http://vps:8000/api/stats/scheduler

# Podsumowanie błędów per moduł (dodane 2026-07-18)
curl -H "X-API-Key: TWOJ_KLUCZ" http://vps:8000/api/logs/error-digest

# Weryfikacja, że kontener widzi aktualny kod z wolumenu
docker compose exec bossoftoys-api grep -n "fragment" /app/api/plik.py

# Rozmiar pluginu WP — test świeżości lokalnej kopii
wc -l wordpress-plugin/bossoftoys-manager/includes/class-bot-admin.php
Rozdział 21

Zasady pracy nad kodem (dla programistów)

Ten projekt ma dojrzałe, spójne konwencje — poniższe zasady dotyczą pracy nad core/, api/ i wordpress-plugin/. Zebrane z .claude/skills/erotivo-dev/ i preferencji zapisanych w .claude/CLAUDE.md.

Twarde zasady projektu

Wzorzec: jak dodać nowy moduł biznesowy

Dostęp do danych — nie omijaj warstw

core/*.py  →  core.data_store.data_store  →  api/repository.py  →  api/database.py  →  SQLite
🚫

Import from core.data_store import data_store zawsze lokalnie, wewnątrz funkcji, nigdy na górze pliku — świadoma konwencja, żeby uniknąć circular importów core↔api. Nigdy nie importuj api.repository bezpośrednio z core/.

Integracje zewnętrzne — gdzie szukać kontraktów API

IntegracjaKlientUwaga
WooCommercecore/api_clients_woo.py (WooCommerceClient)Konstruktor wymaga url, key, secret, logger= — brak logger to częsty błąd kopiowania kodu. Atrybut to .wcapi, nie .client.
BossOfToyscore/boss_api_client.py, core/api_clients_woo.py (BossoftoysAPIClient)Znany bug API dostawcy: TotalItemsCount zawsze = page_size — paginacja musi iterować while len(page) == page_size, nie po TotalItemsCount.
Allegrocore/allegro_client.pyPatrz pełna lista pułapek w rozdziale Moduły Allegro. Multi-konto to plan, NIE implementacja.
ShipX (InPost)core/shipx_client.py, core/shipx_label_generator.pyOsobna umowa od Allegro Delivery.
Empik (Mirakl)core/empik_client.pyOR23 ≠ OR24 (tracking vs. potwierdzenie wysyłki). Plugin empik-for-woocommerce wrzuca kod paczkomatu w shipping.last_name.
Ceneo Kup Terazcore/ceneo_client.pyLogika inline w label_auto_generator.py/shipment_tracking.py, nie osobny CRON job.
Fakturownia.plcore/fakturownia_client.pyAuto-faktury po zmianie statusu zamówienia.

WordPress plugin — dodatkowa ostrożność

🚨

Zanim zrobisz nieaddytywną zmianę w wordpress-plugin/ — zapytaj użytkownika, czy lokalna kopia jest aktualna, albo poproś o świeży plik/backup. Preferuj zmiany addytywne (nowa metoda/funkcja/sekcja dopisana obok istniejącego kodu, kotwiczona o stabilny, unikalny fragment tekstu) nad przepisywaniem całych plików od zera. Zob. incydent w rozdziale Znane problemy, punkt 14 — to nie jest zasada teoretyczna.

Deploy — dwie osobne procedury

Nie myl ich — pełne szczegóły w rozdziale Wdrożenie. W skrócie: backend Python (VPS/Docker) wymaga docker compose restart (plik .py) lub down && up -d (zmiana docker-compose.yml); plugin WordPress działa od razu po wgraniu FTP, ale wymaga bumpnięcia BOT_VERSION przy zmianach JS/CSS.

Zanim zaczniesz zmieniać kod — checklist

  1. find core api -name "*.py" / Glob — zweryfikuj, że moduł faktycznie tak się nazywa.
  2. Sprawdź, czy podobny wzorzec już istnieje gdzie indziej w core/ (47 modułów = 47 przykładów konwencji) zamiast wymyślać nowy styl.
  3. Dla zmian w core/ — pamiętaj o lazy imports data_store i wymaganym logger= w WooCommerceClient.
  4. Dla zmian w Allegro — sprawdź listę pułapek API w rozdziale Moduły Allegro.
  5. Dla zmian w wordpress-plugin/ — zweryfikuj świeżość kopii (wc -l class-bot-admin.php ~3800 linii) i preferuj zmiany addytywne.
  6. Po zmianie: python -m py_compile <plik>, a dla WordPress: php -l/policz nawiasy + node --check dla JS.
  7. Zapytaj użytkownika przed każdą operacją nieodwracalną/współdzieloną (deploy na VPS, restart kontenera produkcyjnego, zmiany na erotivo.pl) — to działający sklep.
Rozdział 22

Słowniczek pojęć i skrótów

TerminZnaczenie
OR23 / OR24Operacje Mirakl API (Empik): OR23 = wysłanie numeru trackingu, OR24 = potwierdzenie wysyłki (SHIPPED). Ceneo ma analogiczne SetOrderShipment/SendOrder.
GPSRGeneral Product Safety Regulation — unijne wymogi dot. danych producenta/importera na ofertach Allegro (m.in. producerData w payloadzie).
WAL (mode)Write-Ahead Logging — tryb SQLite pozwalający na równoczesny odczyt i zapis bez blokowania całej bazy.
TTLTime To Live — czas ważności wpisu w cache, po którym dane są uznawane za nieaktualne.
dryRun / DRY-RUNTryb symulacji — operacja jest logowana/liczona, ale nie wykonywana naprawdę. Domyślny dla operacji destrukcyjnych w tym projekcie.
Ghost trackingMechanizm śledzący, od kiedy produkt jest nieobecny u dostawcy, żeby po X dniach wyzerować stan lub usunąć produkt.
FulfillmentW kontekście Allegro: proces informowania marketplace'u o statusie realizacji zamówienia (PROCESSING/SENT/CANCELLED).
Attribution (WC)Mechanizm WooCommerce pokazujący "Pochodzenie" zamówienia w liście zamówień — sterowany meta _wc_order_attribution_*.
SSEServer-Sent Events — jednokierunkowy strumień zdarzeń HTTP z serwera do przeglądarki, używany do logów live w Dashboardzie.
MODULE_MAPSłownik w api/worker.py mapujący ModuleType (string z URL-a) na funkcję run() konkretnego modułu core/.
BeeIntegroNazwa handlowa/wyświetlana pluginu WordPress, którego katalog roboczy nazywa się historycznie bossoftoys-manager.
GeowidgetWidget InPost do wyboru paczkomatu docelowego na checkout WooCommerce.
Smart wymiary / gabarytAutomatyczny dobór rozmiaru paczki InPost (A/B/C/kurier) na bazie meta produktów w zamówieniu — bierze największy z nich.
NTFYUsługa powiadomień push (self-hosted lub ntfy.sh) używana do alertów krytycznych z VPS na telefon/desktop.
Checkpoint / resumeMechanizm zapisywania postępu długotrwałej operacji (np. Product Adder), żeby po przerwaniu wznowić od ostatniego punktu zamiast zaczynać od zera.